package edu.isistan.matching.utils;

import java.util.Hashtable;

public class ArrayFunctions {

	public static final int SORT_ASCENDING = 1; // Quick sort ascending
	public static final int SORT_DESCENDING = 2; // Quick sort descending

	/** Find element in an object array */
	public static boolean findElement(Object[] array, Object element) {
		if (array == null)
			return false;
		for (int i = 0; i < array.length; i++) {
			if (array[i].equals(element)) {
				return true;
			}
		}
		return false;
	}

	/** Finds the largest element in a positive array */
	public static double findLargest(double[][] array) {
		double largest = 0;
		for (int i = 0; i < array.length; i++) {
			for (int j = 0; j < array[i].length; j++) {
				if (array[i][j] > largest) {
					largest = array[i][j];
				}
			}
		}
		return largest;
	}

	/** Transposes a double[][] array */
	public static double[][] transpose(double[][] array) {
		double[][] transposedArray = new double[array[0].length][array.length];
		for (int i = 0; i < transposedArray.length; i++) {
			for (int j = 0; j < transposedArray[i].length; j++) {
				transposedArray[i][j] = array[j][i];
			}
		}
		return transposedArray;
	}
	
	/** Transposes a int[][] array */
	public static int[][] transpose(int[][] array) {
		int[][] transposedArray = new int[array[0].length][array.length];
		for (int i = 0; i < transposedArray.length; i++) {
			for (int j = 0; j < transposedArray[i].length; j++) {
				transposedArray[i][j] = array[j][i];
			}
		}
		return transposedArray;
	}

	/** Copies all elements of an array to a new array */
	public static double[][] copyOf(double[][] original) {
		double[][] copy = new double[original.length][original[0].length];
		for (int i = 0; i < original.length; i++) {
			System.arraycopy(original[i], 0, copy[i], 0, original[i].length);
		}
		return copy;
	}

	/** Copy a part of an array to a new array */
	public static double[][] copyOf(double[][] array, int ind1, int length1, int ind2, int length2) {
		double res[][] = new double[length1][length2];
		for (int j1 = 0; j1 < length1; j1++) {
			System.arraycopy(array[ind1 + j1], ind2, res[j1], 0, length2);
		}
		return res;
	}

	/** Calculate scalar product (x, y) of vectors x and y */
	public static double scalarProduct(int m, double[] x, double[] y) {
		double res = 0;
		for (int i = 0; i < m; i++) {
			res += x[i] * y[i];
		}
		return res;
	}

	/** Calculate similarity score of two vectors */
	public static double cosineSimilarity(int m, double[] x1, double[] x2) {
		double tmp = java.lang.Math.sqrt(scalarProduct(m, x1, x1)) * java.lang.Math.sqrt(scalarProduct(m, x2, x2));
		if (tmp == 0)
			return 0;
		double res = scalarProduct(m, x1, x2) / tmp;
		return res;
	}

	/** Create similarity matrix for two arrays */
	public static double[][] cosineSimilarityMatrix(Hashtable wordIndex, double[][] vectors1, double[][] vectors2) {
		double[][] partSim = new double[vectors1.length][vectors2.length];
		for (int i = 0; i < vectors1.length; i++) {
			for (int j = 0; j < vectors2.length; j++)
				partSim[i][j] = cosineSimilarity(wordIndex.size(), vectors1[i], vectors2[j]);
		}
		return partSim;
	}

	/** Summarize the array elements */
	public static double getSum(double[] res) {
		double sum = 0;
		for (int i = 0; i < res.length; i++) {
			sum += res[i];
		}
		return sum;
	}

	/** Calculate average of array elements */
	public static double getAverage(double[] res) {
		if (res.length == 0)
			return 0;
		return (getSum(res) / res.length);
	}

	/* Quick sort (http://www.geocities.com/herong_yang/sort/quick.html) */
	public static void quickSort(Object[] array, int fromIndex, int toIndex, int type) {
		Object d;
		if (toIndex - fromIndex <= 1) {
			return;
		} else if (toIndex - fromIndex == 2) {
			if (type == SORT_DESCENDING) {
				if (((Comparable) array[fromIndex]).compareTo(array[toIndex - 1]) < 0) {
					d = array[toIndex - 1];
					array[toIndex - 1] = array[fromIndex];
					array[fromIndex] = d;
				}
			} else {
				if (((Comparable) array[fromIndex]).compareTo(array[toIndex - 1]) > 0) {
					d = array[toIndex - 1];
					array[toIndex - 1] = array[fromIndex];
					array[fromIndex] = d;
				}
			}
		} else {
			int iLeft = fromIndex + 1;
			int iRight = toIndex - 1;
			Comparable p = (Comparable) array[fromIndex];
			while (iLeft < iRight) {
				if (type == SORT_DESCENDING) {
					while (iLeft < toIndex - 1 && (p.compareTo(array[iLeft]) <= 0)) {
						iLeft++;
					}
				} else {
					while (iLeft < toIndex - 1 && p.compareTo(array[iLeft]) >= 0) {
						iLeft++;
					}
				}

				if (type == SORT_DESCENDING) {
					while (iRight > fromIndex + 1 && p.compareTo(array[iRight]) >= 0) {
						iRight--;
					}
				} else {
					while (iRight > fromIndex + 1 && p.compareTo(array[iRight]) <= 0) {
						iRight--;
					}
				}
				if (iLeft >= iRight) {
					break;
				}

				d = array[iRight];
				array[iRight] = array[iLeft];
				array[iLeft] = d;
			}

			if (iLeft > fromIndex + 1) {
				d = array[iRight];
				array[iRight] = array[fromIndex];
				array[fromIndex] = d;
			}

			if (iLeft == iRight && iRight == toIndex) {
				quickSort(array, fromIndex, iRight, type);
			} else if (iLeft == iRight && iRight == fromIndex) {
				quickSort(array, iLeft, toIndex, type);
			} else {
				quickSort(array, fromIndex, iRight, type);
				quickSort(array, iLeft, toIndex, type);
			}
		}
	}
}
